package cn.iocoder.yudao.module.ai.controller.admin.modelfactory;

import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.ai.controller.admin.busimodel.vo.BusiModelAndParamVO;
import cn.iocoder.yudao.module.ai.controller.admin.modelfactoryparam.vo.ModelFactoryAndParamVO;
import cn.iocoder.yudao.module.ai.dal.dataobject.busimodelparam.BusiModelParamDO;
import cn.iocoder.yudao.module.ai.service.busimodel.BusiModelService;
import cn.iocoder.yudao.module.ai.service.jupyter.JupyterService;
import cn.iocoder.yudao.module.ai.service.modelfactoryparam.ModelFactoryParamService;
import cn.iocoder.yudao.module.ai.utils.AssertUtil;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.io.File;
import java.io.FileInputStream;
import java.util.*;
import java.io.IOException;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;

import cn.iocoder.yudao.module.ai.controller.admin.modelfactory.vo.*;
import cn.iocoder.yudao.module.ai.dal.dataobject.modelfactory.ModelFactoryDO;
import cn.iocoder.yudao.module.ai.service.modelfactory.ModelFactoryService;

@Tag(name = "管理后台 - 模型车间")
@RestController
@RequestMapping("/ai/modelFactory")
@Validated
@Slf4j
public class ModelFactoryController {

    @Resource
    private ModelFactoryService modelFactoryService;

    @Resource
    private BusiModelService busiModelService;

    @Value("${modelFactory.build-path}")
    private String buildPath;

    //公共上传地址
    @Value("${yudao.file.upload-path}")
    private String commonPath;

    @Resource
    private DeptApi deptApi;

    /**
     * 手动构建模型（第一步） ：保存模型基本信息以及识别模型信息
     * @param createReqVO
     * @return
     */
    @PostMapping("/create")
    @Operation(summary = "手动构建模型（第一步）")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:create')")
    public CommonResult<Long> createModelFactory(@Valid @RequestBody ModelFactorySaveReqVO createReqVO) {
        log.info("开始手动构建模型：");
        createReqVO.setSuplierId(deptApi.queryFirstDept(SecurityFrameworkUtils.getLoginUserDeptId()));
        log.info("手动构建模型，保存模型基本信息：{}", JSONObject.toJSONString(createReqVO));
        return success( modelFactoryService.createModelFactory(createReqVO));
    }

    /**
     * 手动构建模型（第二步） ：保存业务模型信息
     * @param createReqVO
     * @return
     */
    @PostMapping("/createSecond")
    @Operation(summary = "手动构建模型（第二步）")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:create')")
    public CommonResult<Boolean> createModelFactorySecond(@Valid @RequestBody ModelFactorySaveReqVO createReqVO) {
        log.info("手动构建模型，保存业务模型信息：");
        if(createReqVO.getBusiModelId() == null) {
           log.info("未选择系统内业务模型，将从jupyter中直接保存并构建此模型。");
        }else{
            log.info("已选择系统内的业务模型，进行构建。");
            BusiModelAndParamVO vo = busiModelService.getBusiModel(createReqVO.getBusiModelId().intValue());
            createReqVO.setJupyterId(vo.getJupyterId());
        }
        AssertUtil.isNotEmpty(createReqVO.getJupyterId(),"构建模型必须选择业务模型。");
        modelFactoryService.updateModelFactory(createReqVO);
        log.info("手动构建模型完成。");
        return success(true);
    }

    /**
     * 构建并下载模型：
     *      最终文件结构:
     *        ---识别模型文件.py
     *        ---env.sh
     *        ---scene.conf
     *        ---业务模型文件夹（固定名称：__pycache__）
     *           ---业务模型文件.py
     * @param
     * @return
     */
    @PostMapping("/buildAndDownloadModel")
    @Operation(summary = "构建并下载模型")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:download')")
    public CommonResult<String> buildAndDownloadModel(@Valid @RequestBody ModelFactoryDO modelFactoryDO,HttpServletRequest request) throws IOException {
        String filePath = modelFactoryService.buildModel(modelFactoryDO);
        return success(getUrl(request,filePath+".zip"));
        /*
        try {
            File file = new File(filePath);
            if (!file.exists() || file.isDirectory()) {
                return ResponseEntity.notFound().build();
            }
            // 读取文件内容
            FileInputStream inputStream = new FileInputStream(file);
            InputStreamResource resource = new InputStreamResource(inputStream);

            // 设置HTTP响应头
            HttpHeaders headers = new HttpHeaders();
            headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + "Model.zip" + "\"");
            headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
            headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(file.length()));

            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(file.length())
                    .body(resource);

        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).build();
        }*/
    }



    @PutMapping("/update")
    @Operation(summary = "更新模型车间")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:update')")
    public CommonResult<Boolean> updateModelFactory(@Valid @RequestBody ModelFactorySaveReqVO updateReqVO) {
        modelFactoryService.updateModelFactory(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除模型车间")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('ai:model-factory:delete')")
    public CommonResult<Boolean> deleteModelFactory(@RequestParam("id") Long id) {
        modelFactoryService.deleteModelFactory(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得模型车间")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:query')")
    public CommonResult<ModelFactoryAndParamVO> getModelFactory(@RequestParam("id") Long id) {
        ModelFactoryAndParamVO modelFactory = modelFactoryService.getModelFactory(id);
        return success(modelFactory);
    }

    @GetMapping("/page")
    @Operation(summary = "获得模型车间分页")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:query')")
    public CommonResult<PageResult<ModelFactoryRespVO>> getModelFactoryPage(@Valid ModelFactoryPageReqVO pageReqVO) {
        PageResult<ModelFactoryDO> pageResult = modelFactoryService.getModelFactoryPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, ModelFactoryRespVO.class));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出模型车间 Excel")
    @PreAuthorize("@ss.hasPermission('ai:model-factory:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportModelFactoryExcel(@Valid ModelFactoryPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ModelFactoryDO> list = modelFactoryService.getModelFactoryPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "模型车间.xls", "数据", ModelFactoryRespVO.class,
                        BeanUtils.toBean(list, ModelFactoryRespVO.class));
    }

    /**
     * 根据相对路径获取可访问的路径
     * @param request
     * @param relativePath
     * @return
     */
    public String getUrl(HttpServletRequest request, String relativePath){

        String scheme = request.getScheme(); // 获取协议（http 或 https）
        String serverName = request.getServerName(); // 获取服务器地址
        int serverPort = request.getServerPort(); // 获取端口号
        String port = serverPort == 80 ? "" : ":" + serverPort;

        relativePath = relativePath.startsWith("/")?relativePath:("/"+relativePath);
        String serverUrl = scheme + "://" + serverName + port;
        return serverUrl+ "/file" + relativePath;
    }

}